﻿////////////////////////////////////////////////////
//
// Copyright (c) 2010, Cristian Daini
// All rights reserved.
// 
// http://laharsubsample.codeplex.com/
//
////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using System.Threading;
using Laharsub.Client;
using System.IO;
using System.Runtime.Serialization;
using System.Text;

namespace Chat
{
    public partial class MainPage : UserControl
    {

        public MainPage()
        {
            InitializeComponent();

            EnableOperations(null, null);
        }

        #region Enable Operations

        void EnableOperations(object sender, TextChangedEventArgs e)
        {
            txtHost.IsEnabled = (this.client == null);
            cmdStart.IsEnabled = (this.client == null) && (HostBox != "");
            cmdPolicy.IsEnabled = (this.client != null);
            cmdRunning.IsEnabled = (this.client != null);
            cmdCreate.IsEnabled = (this.client != null);
            cmdSubscribe.IsEnabled = (this.client != null) && (topicBox > 0);
            cmdUnsubscribe.IsEnabled = (this.client != null) && (topicBox > 0);
            cmdUnsubscribeAll.IsEnabled = (this.client != null);
            cmdPublish.IsEnabled = (this.client != null) && (topicBox > 0) && (messageBox != "");
            cmdPublishData.IsEnabled = (this.client != null) && (topicBox > 0) && (messageBox != "");
        }

        #endregion

        #region Laharsub

        PubsubClient client;


        string HostBox
        {
            get
            {
                return txtHost.Text.Trim();
            }
        }


        string Host
        {
            get
            {
                return "http://" + HostBox + "/";
            }
        }


        private void cmdStart_Click(object sender, RoutedEventArgs e)
        {
            const string backend = "memory";
            string baseAddress = Host + "ps/" + backend;
            this.client = new Laharsub.Client.PubsubClient(baseAddress);

            AddLineChatBox(chat.client, "Laharsub hosted at [{0}]", Host);
            EnableOperations(null, null);
        }


        // Is Laharsub Running?
        private void cmdRunning_Click(object sender, RoutedEventArgs e)
        {
            this.client.CreateTopicAsync(
                delegate(int topicId)
                {
                    AddLineChatBox(chat.server, "Laharsub server is running");
                },
                delegate(Exception ex)
                {
                    AddLineChatBox(chat.client, "Laharsub server is not running");
                }
            );
        }

        #endregion

        #region Verify Access Policy

        private void cmdPolicy_Click(object sender, RoutedEventArgs e)
        {
            // Verify Connection
            AddLineChatBox(chat.debug, "Test for connection with [{0}]", Host);
            VerifyConnection.IsConnectionAvailable(Host,
                delegate()
                {
                    AddLineChatBox(chat.client, "Connection to [{0}] is available", Host);
                },
                delegate(Exception ex)
                {
                    AddLineChatBox(chat.error, "Connection to [{0}] is not available", Host);
                    // AddLineChatBox(chat.error, "Connection to [{0}] is not available [[ {1} ]]", Host, ex);
                });

            // Verify Access Policy
            string policyFileAddress = Host + "clientaccesspolicy.xml";
            AddLineChatBox(chat.debug, "Test for file [{0}]", policyFileAddress);
            VerifyConnection.IsFileAccessible(policyFileAddress,
                delegate()
                {
                    AddLineChatBox(chat.client, "ClientAccessPolicy.xml file is accessible at [{0}].", policyFileAddress);
                },
                delegate(Exception ex)
                {
                    AddLineChatBox(chat.error, "ClientAccessPolicy.xml file is not accessible at [{0}].", policyFileAddress);
                    AddLineChatBox(chat.error, "Please check the clientaccesspolicy.xml file in the Laharsub.Client.Silverlight.Test.Web project for more information.");
                    // AddLineChatBox(chat.error, "[[ {0} ]]", ex);
                });
        }

        #endregion

        #region Topic Box

        int topicBox
        {
            get
            {
                int topicId = 0;
                int.TryParse(txtTopic.Text, out topicId);
                return topicId;
            }
            set
            {
                txtTopic.Text = value.ToString();
            }
        }

        #endregion

        #region Message Box

        private void txtMessage_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter && cmdPublish.IsEnabled)
            {
                cmdPublish_Click(sender, null);
            }
        }


        string messageBox
        {
            get
            {
                return txtMessage.Text.Trim();
            }
            set
            {
                txtMessage.Text = value;
                txtMessage.Focus();
            }
        }

        #endregion

        #region Chat Box

        bool showDebugLines = true;

        enum chat
        {
            debug,
            client,
            server,
            error,
        }


        /// <summary>
        /// Add a message to the Chat box
        /// </summary>
        void AddLineChatBox(chat mode, string line, params object[] args)
        {
            if (mode != chat.debug || showDebugLines)
            {
                line = string.Format(line, args);
                Chat.Text += string.Format("({0}) [{1}] {2}\n", DateTime.Now.ToString("HH:mm:ss"), mode.ToString(), line);
                Chat.Select(Chat.Text.Length - 1, 0);
            }
        }

        #endregion

        #region Create a Topic

        private void cmdCreate_Click(object sender, RoutedEventArgs e)
        {
            AddLineChatBox(chat.debug, "Begin CreateTopicAsync");
            cmdCreate.IsEnabled = false;
            this.client.CreateTopicAsync(
                delegate(int topicId)
                {
                    AddLineChatBox(chat.server, "Created the topic [{0}]", topicId);
                    topicBox = topicId;
                    cmdCreate.IsEnabled = true;
                },
                delegate(Exception ex)
                {
                    AddLineChatBox(chat.error, "CreateTopicAsync: [[ {0} ]]", ex);
                    cmdCreate.IsEnabled = true;
                }
            );
        }

        #endregion

        #region Subscribe to topic / Unsubscribe

        private void cmdSubscribe_Click(object sender, RoutedEventArgs e)
        {
            AddLineChatBox(chat.client, "Subscribe to topic [{0}]", topicBox);
            this.client.SubscribeAsync(topicBox,
                delegate(Subscription s, PubsubMessage lhMessage)
                {
                    AddLineChatBox(chat.server, "Receive Message [{0}] : [{1}]", lhMessage.MessageId, lhMessage.GetBodyAsString());
                },
                delegate(Subscription s, Exception ex)
                {
                    AddLineChatBox(chat.error, "SubscribeAsync: topic [{0}] [[ {1} ]]", s.TopicId, ex);
                }
            );
        }


        private void cmdUnsubscribe_Click(object sender, RoutedEventArgs e)
        {
            AddLineChatBox(chat.debug, "Unsubscribe from topic [{0}]", topicBox);
            this.client.Unsubscribe(topicBox);
        }


        private void cmdUnsubscribeAll_Click(object sender, RoutedEventArgs e)
        {
            AddLineChatBox(chat.debug, "Unsubscribe from all topics");
            this.client.UnsubscribeAll();
        }

        #endregion

        #region Publish Message

        private void cmdPublish_Click(object sender, RoutedEventArgs e)
        {
            AddLineChatBox(chat.debug, "Begin PublishAsync Topic [{0}] Message [{1}]", topicBox, messageBox);
            cmdPublish.IsEnabled = false;
            this.client.PublishAsync(topicBox, messageBox,
                    delegate(PubsubMessage lhMessage)
                    {
                        AddLineChatBox(chat.server, "Publish topic [{0}] messageId [{1}] : [{2}]", lhMessage.TopicId, lhMessage.MessageId, lhMessage.GetBodyAsString());
                        EnableOperations(null, null);
                    },
                    delegate(PubsubMessage lhMessage, Exception ex)
                    {
                        AddLineChatBox(chat.error, "PublishAsync: topic [{0}] [[ {1} ]]", lhMessage.TopicId, ex);
                        EnableOperations(null, null);
                    }
                );

            messageBox = "";
        }

        #endregion

        #region Subscribe/Publish Data

        private void cmdSubscribeData_Click(object sender, RoutedEventArgs e)
        {
            AddLineChatBox(chat.client, "Subscribe to Data from topic [{0}]", topicBox);
            this.client.SubscribeAsync(topicBox,
                delegate(Subscription s, PubsubMessage lhMessage)
                {
                    DataMessage data = DataMessage.FromStream(lhMessage.Body);
                    AddLineChatBox(chat.server, "Receive data. [{0}] > [{1}] : [{2}]", data.source, data.target, data.content);
                },
                delegate(Subscription s, Exception ex)
                {
                    AddLineChatBox(chat.error, "SubscribeAsync: topic [{0}] [[ {1} ]]", s.TopicId, ex);
                }
            );
        }


        static string source = "user_" + new Random().Next(100);


        private void cmdPublishData_Click(object sender, RoutedEventArgs e)
        {
            AddLineChatBox(chat.debug, "Begin PublishAsync Topic [{0}] Message [{1}]", topicBox, messageBox);
            cmdPublishData.IsEnabled = false;

            DataMessage data = new DataMessage
            {
                source = source,
                target = "chatroom",
                content = messageBox,
                someBinary = new byte[] { 0, 1, 2, 3, 218 }
            };

            PubsubMessage lhMessage = new PubsubMessage
            {
                TopicId = topicBox,
                ContentType = "application/chat",
                Body = data.ToStream()
            };

            this.client.PublishAsync(lhMessage,
                    delegate(PubsubMessage lhMessage1)
                    {
                        AddLineChatBox(chat.server, "Publish data. [{0}] > [{1}] : [{2}]", data.source, data.target, data.content);
                        EnableOperations(null, null);
                    },
                    delegate(PubsubMessage lhMessage1, Exception ex)
                    {
                        AddLineChatBox(chat.error, "PublishAsync: topic [{0}] [[ {1} ]]", lhMessage1.TopicId, ex);
                        EnableOperations(null, null);
                    }
                );

            messageBox = "";
        }


        #endregion
    }
}
